home *** CD-ROM | disk | FTP | other *** search
- #import "TiffManager.h"
- #import "Thinker.h"
-
- //I tested on 32Mb memory workstation
- //it caused flicker if bigger than this
- #define MAXIMAGESIZE 150 //scale down if bigger than this
-
- #define SIZEINC 2 //increase image by number of pixels
- // for each frame in animation
- // this will affect how many images will
- //be built for each animation
- //the smaller the increment the smoother it is
-
- //#define DEBUG
-
- @implementation TiffManager
-
- - init
- {
- char buf[MAXPATHLEN + 1];
-
- buf[0] = (int)NULL;
- [super init];
-
- [self setHomeDirFile:buf]; //if there is a .Celestial folder in
- //home directory - use it instead
-
- [self setTiffDirectory :buf];
-
- [self buildTiffStorage];
-
- if (totalTiffCount < 1){ //no files in .Celestial folder
- // get them from module folder
-
- moduleDir = [[NXApp delegate] moduleDirectory:"StarShip"];
- strcpy(buf, moduleDir);
- strcat(buf,"/Celestial.bundle");
- [self setTiffDirectory :buf];
- [self buildTiffStorage];
-
- }
- else
- printf("Using files in .Celestial folder\n");
-
- tiffStorageIndex = 0;
- animationIndex = 0;
- numberProcessed = 0;
- animFileIndex = 1;
- maxAnimFiles = 0;
- return self;
-
- }
-
-
- //looks in the tiffStorage and starts creating images one at a time
- //and returns so that something else can be going on while this is
- //happening - returns Done when they are created.
-
- - (BOOL)createTiffs
- {
-
- char buf[MAXPATHLEN + 1];
- char *imageName = 0;
- char *animDirName = 0;
- ImageStruct imageStruct;
- int isSpin = 0;
- int isAnim = 0;
- int isMult = 0;
- #ifdef DEBUG
- NXRect DebugRect;
- #endif
-
-
- NXPoint bogusPoint = {0.0,0.0}; //composite image to create cache
- NXRect bogusRect = {0.0,0.0,1.0,1.0}; //composite image to create cache
- float increasePercent;
- NXPoint offset;
- NXPoint oldCenter;
- NXPoint newCenter;
- NXPoint newTrans;
- float distance,origAngle,maxDiagonal;
-
-
- // tiffStorageIndex = 0 to totalTiffCount-1
-
- isSpin = ((ImageStruct *)[tiffStorage elementAt:
- tiffStorageIndex])->isSpin;
- isMult = ((ImageStruct *)[tiffStorage elementAt:
- tiffStorageIndex])->isMult;
- isAnim = ((ImageStruct *)[tiffStorage elementAt:
- tiffStorageIndex])->isAnim;
- maxAnimFiles = ((ImageStruct *)[tiffStorage elementAt:
- tiffStorageIndex])->maxAnimFiles;
- imageName = ((ImageStruct *)[tiffStorage elementAt:
- tiffStorageIndex])->imageName;
- animDirName = ((ImageStruct *)[tiffStorage elementAt:
- tiffStorageIndex])->animDirName;
-
-
- switch(animationIndex){
- case 0: //create list - read in source Image
- spinAdjustRect.origin.x = 0.0;
- spinAdjustRect.origin.y = 0.0;
- scaledImageRect.origin.x = 0.0;
- scaledImageRect.origin.y = 0.0;
-
- localImageList = [[List alloc] init];
- if(isAnim){ // drop down another level
- sprintf(buf,"%s/%s.anim/%s.%d.tiff",tiffDirectory, animDirName,
- imageName,animFileIndex);
- animFileIndex++;
- if(animFileIndex > maxAnimFiles)
- animFileIndex = 1;
- }
- else
- sprintf(buf,"%s/%s.tiff",tiffDirectory,imageName);
-
- sourceImage = [[NXBitmapImageRep alloc] initFromFile:buf];
- if(sourceImage == nil){
- printf("couldn't init NXBitmapImageRep from file %s\n",buf);
- animationIndex = 0; //get next image if there is one
- tiffStorageIndex++;
- if(tiffStorageIndex > totalTiffCount)
- tiffStorageIndex = 0;
- numberProcessed++;
- break;
- }
- else animationIndex++;
- if(isSpin){
- angle = 0.0;
- angleInc = randBetween(5,10); // objects will spin
- //at different speeds each time
- }
- break;
- case 1: //create temp buffer size of original image unless spinning
- // if spinning make buffer square
-
- [sourceImage getSize: &sourceImageSize];
-
-
- if(sourceImageSize.width > sourceImageSize.height){
- widthIsSmaller = NO;
- scaledImageRect.size.height = 1;
- //get percentage that 1 pixel is
- increasePercent = scaledImageRect.size.height /
- sourceImageSize.height;
- scaledImageRect.size.width = ceil(increasePercent *
- sourceImageSize.width);
- maxImageSize = (sourceImageSize.width > MAXIMAGESIZE) ?
- MAXIMAGESIZE: sourceImageSize.width; // smallest number
- }
- else{
- widthIsSmaller = YES;
- scaledImageRect.size.width = 1;
- //get percentage that 1 pixel is
- increasePercent = scaledImageRect.size.width /
- sourceImageSize.width;
- scaledImageRect.size.height = ceil(increasePercent *
- sourceImageSize.height);
- maxImageSize = (sourceImageSize.height > MAXIMAGESIZE) ?
- MAXIMAGESIZE: sourceImageSize.height; //smallest number
-
- }
- if(isSpin){ //use diagonal across original image to make a square
- // big enough to handle the image rotating
- maxDiagonal = sqrt((sourceImageSize.width *
- sourceImageSize.width) +
- (sourceImageSize.height * sourceImageSize.height));
- spinAdjustRect.size.height = spinAdjustRect.size.width
- = maxDiagonal;
- //get center of the new buffer
- spinCenter.x = spinAdjustRect.size.width / 2;
- spinCenter.y = spinAdjustRect.size.height / 2;
-
- buffer = [[NXImage allocFromZone:[self zone]]
- initSize:&spinAdjustRect.size];
- }
- else{
- buffer = [[NXImage allocFromZone:[self zone]]
- initSize:&sourceImageSize];
- }
-
- animationIndex++;
- break;
- case 2: // scale and/or rotate - composite the image in buffer
- // this will keep alpha info
- // when you do the rotate, it rotates around origin
- // have to do a translate to bring center of image
- //back to the same place. drawIn method will do the
- //scaling automatically
- if([buffer lockFocus]){
- if(isSpin){
-
- //caculate the real size of the animation images
-
- scaledDiagonal = sqrt((scaledImageRect.size.width *
- scaledImageRect.size.width)
- + (scaledImageRect.size.height *
- scaledImageRect.size.height));
- spinScaledImageRect.size.width = scaledDiagonal;
- spinScaledImageRect.size.height = scaledDiagonal;
-
- //find the orgin of where the scaled image is in buffer
-
- spinScaledImageRect.origin.x =(spinCenter.x -
- (scaledDiagonal/2));
- spinScaledImageRect.origin.y = (spinCenter.y -
- (scaledDiagonal/2));
- PSsetgray(0);// black out buffer
- NXRectFill(&spinScaledImageRect);//black out part of buffer
-
- oldCenter.x = scaledImageRect.size.width / 2;
- oldCenter.y = scaledImageRect.size.height / 2;
-
- origAngle = atan(oldCenter.y/oldCenter.x);
-
-
- distance = sqrt((oldCenter.x * oldCenter.x) +
- (oldCenter.y * oldCenter.y));
- angle += angleInc; //increment the angle
-
- // convert degrees to radians
-
- newCenter.x = cos(origAngle + (angle/57.30)) * distance;
- newCenter.y = sin(origAngle + (angle/57.30)) * distance;
- newTrans.x = (oldCenter.x - newCenter.x);
- newTrans.y = (oldCenter.y - newCenter.y);
-
- //now adjust to center of square buffer
- newTrans.x += (spinCenter.x - oldCenter.x);
- newTrans.y += (spinCenter.y - oldCenter.y);
-
- PStranslate(0.0 + newTrans.x,0.0 + newTrans.y);
- PSrotate(angle);
-
-
- if(![sourceImage drawIn:&scaledImageRect])
- printf("resizing image didn't work\n");
- [buffer unlockFocus];
- }
- else {
- if(![sourceImage drawIn:&scaledImageRect])
- printf("resizing image didn't work\n");
- [buffer unlockFocus];
- }
- }
- if(isAnim){
- [sourceImage free];
- }
- animationIndex++;
- break;
- case 3: // create new image correct size
- //build the image object with the actual image centered
- //in a black rectangle 8 pixels bigger on all sides
- // the stars have a max of width and height of 7
- // and this guarantees that they will get blacked out
- // as the image is moving
- if(isSpin){
- //calculate a square from the scaled image size
- // using the diagonal across the scaled image
-
- adjustedRect.origin.x = 0.0;
- adjustedRect.origin.y = 0.0;
- adjustedRect.size.width = scaledDiagonal+16;
- adjustedRect.size.height = scaledDiagonal+16;
-
- //create the actual image 16 pixels bigger
-
- image = [[NXImage allocFromZone:[self zone]]
- initSize:&adjustedRect.size];
-
- //black it out
- if([image lockFocus]){
- PSsetgray(0);
- NXRectFill(&adjustedRect); //black out new image
- [image unlockFocus];
- }
-
- }
- else{
- adjustedRect.origin.x = 0.0;
- adjustedRect.origin.y = 0.0;
- adjustedRect.size.width = scaledImageRect.size.width+16;
- adjustedRect.size.height = scaledImageRect.size.height+16;
-
-
- //create the image
-
- image = [[NXImage allocFromZone:[self zone]]
- initSize:&adjustedRect.size];
- if([image lockFocus]){
- PSsetgray(0);
- NXRectFill(&adjustedRect); //black out new image
- [image unlockFocus];
- }
- }
- animationIndex++;
- break;
- case 4: //composite into the image just created to get rid of alpha
- //center in middle of slightly bigger black image if rotating
-
- offset.x = 8.0;
- offset.y = 8.0;
- if([image lockFocus]){
- if(isSpin){
- [buffer composite:NX_SOVER fromRect:&spinScaledImageRect
- toPoint:&offset];
- }
- else{
- [buffer composite:NX_SOVER fromRect:&scaledImageRect
- toPoint:&offset];
- }
-
- [image unlockFocus];
- }
- animationIndex++;
- break;
- case 5: //now do phony composite, to build
- //offscreen cache - othewise a delay will happen
- //when you composite the first one
-
- #ifdef DEBUG
- //special debug code to see actual images being generated
- // set PSsetgray(1) on previous calls to see the buffers
- PSsetgray(0);
- bogusPoint.x = 250.0;
- bogusPoint.y = 250.0;
- DebugRect.origin.x = 0.0;
- DebugRect.origin.y = 0.0;
-
- [image getSize: &DebugRect.size];
- [image composite:NX_SOVER fromRect:&DebugRect
- toPoint:&bogusPoint];
-
- bogusPoint.x = 50.0;
- bogusPoint.y = 50.0;
-
- [buffer getSize: &DebugRect.size];
- [buffer composite:NX_SOVER fromRect:&DebugRect
- toPoint:&bogusPoint];
-
- if(isSpin){
- PSmoveto(spinScaledImageRect.origin.x+50,
- spinScaledImageRect.origin.y+50);
- PSlineto(spinScaledImageRect.origin.x+50,
- spinScaledImageRect.origin.y + spinScaledImageRect.size.height+50);
- PSlineto(spinScaledImageRect.origin.x+50 + spinScaledImageRect.size.width,
- spinScaledImageRect.origin.y + spinScaledImageRect.size.height+50);
- PSlineto(spinScaledImageRect.origin.x + spinScaledImageRect.size.width+50,
- spinScaledImageRect.origin.y+50);
- PSlineto(spinScaledImageRect.origin.x+50,spinScaledImageRect.origin.y+50);
- }
- else {
- PSmoveto(scaledImageRect.origin.x+50, scaledImageRect.origin.y+50);
- PSlineto(scaledImageRect.origin.x+50, scaledImageRect.origin.y +
- scaledImageRect.size.height+50);
- PSlineto(scaledImageRect.origin.x+50 + scaledImageRect.size.width,
- scaledImageRect.origin.y + scaledImageRect.size.height+50);
- PSlineto(scaledImageRect.origin.x + scaledImageRect.size.width+50,
- scaledImageRect.origin.y+50);
- PSlineto(scaledImageRect.origin.x+50, scaledImageRect.origin.y+50);
- }
- PSstroke();
- #else
- [image composite:NX_DOVER fromRect:&bogusRect
- toPoint:&bogusPoint];
- #endif
-
-
- [localImageList addObject:image]; //add to list
-
- //calculate new size
- if(widthIsSmaller){
- scaledImageRect.size.width += SIZEINC;
- scaledImageRect.size.width =
- ceil(scaledImageRect.size.width);
- scaledImageRect.size.height =
- ceil((scaledImageRect.size.width /
- sourceImageSize.width) * sourceImageSize.height);
- }
- else{
- scaledImageRect.size.height += SIZEINC;
- scaledImageRect.size.height =
- ceil(scaledImageRect.size.height);
- scaledImageRect.size.width =
- ceil((scaledImageRect.size.height /
- sourceImageSize.height) * sourceImageSize.width);
-
- }
-
- // if image is now bigger that max allowed size - exit on next pass
-
- if (scaledImageRect.size.width <= maxImageSize &&
- scaledImageRect.size.height <= maxImageSize){
- animationIndex = 2;
- if(isAnim){ // set source image to next one
- sprintf(buf,"%s/%s.anim/%s.%d.tiff",
- tiffDirectory, animDirName,imageName,animFileIndex);
- animFileIndex++;
- if(animFileIndex > maxAnimFiles)
- animFileIndex = 1;
-
- //create image for next pass if anim type
- sourceImage = [[NXBitmapImageRep alloc] initFromFile:buf];
- if(sourceImage == nil){//bad anim dir - go on to next image
- printf("couldn't init image file %s\n",buf);
- printf("skipping anim directory\n");
- if([buffer free] != nil)
- printf("buffer not freed\n");;
- numberProcessed++;
- tiffStorageIndex++;
- if(tiffStorageIndex > totalTiffCount)
- tiffStorageIndex = 0;
- }
- }
- }
- else{
- animationIndex++;
- }
- break;
- case 6: // finish image list
- //printf("completing image # %d\n", tiffStorageIndex);
- numberProcessed++;
- if(!isAnim){
- [sourceImage free];
- }
- if([buffer free] != nil)
- printf("buffer not freed\n");
-
- imageStruct.imageList = localImageList;
- imageStruct.imageName = imageName;
- imageStruct.isSpin = isSpin;
- imageStruct.isMult = isMult;
- imageStruct.isAnim = isAnim;
- imageStruct.animDirName = animDirName;
- imageStruct.maxAnimFiles = maxAnimFiles;
- [tiffStorage replaceElementAt:(unsigned int)tiffStorageIndex
- with:&imageStruct];
- animationIndex = 0;
- animFileIndex = 1;
- tiffStorageIndex++;
- if(tiffStorageIndex >= totalTiffCount)
- tiffStorageIndex = 0;
- break;
- }
-
- if(numberProcessed >= MAXANIMATIONS || numberProcessed >= totalTiffCount){
- numberProcessed = 0;
- return NO;
- }
- else{
- return YES; //Tiffs still need to be built
- }
- }
- - freeTiffs
- {
- // all the tiffs brought in
- int ii;
-
- List *imageList;
- int count;
- char *imageName = 0;
- char *animDirName = 0;
- ImageStruct imageStruct;
- int isSpin = 0;
- int isAnim = 0;
- int isMult = 0;
-
-
- for(ii=0; ii < (int)[tiffStorage count];ii++){
- imageList = (List *)((ImageStruct *)[tiffStorage
- elementAt:ii])->imageList;
- if(imageList != nil){
- count = [imageList count];
- if(count){
- [imageList freeObjects];
- [imageList free];
- //kind of ugly - all this to set the storage item
- //imageStruct.imageList to nil - otherwise
- // all other variables in storage record get wiped out
-
- isSpin = ((ImageStruct *)[tiffStorage elementAt:
- ii])->isSpin;
- isMult = ((ImageStruct *)[tiffStorage elementAt:
- ii])->isMult;
- isAnim = ((ImageStruct *)[tiffStorage elementAt:
- ii])->isAnim;
- maxAnimFiles = ((ImageStruct *)[tiffStorage elementAt:
- ii])->maxAnimFiles;
- imageName = ((ImageStruct *)[tiffStorage elementAt:
- ii])->imageName;
- animDirName = ((ImageStruct *)[tiffStorage elementAt:
- ii])->animDirName;
- imageStruct.imageList = nil;
- imageStruct.imageName = imageName;
- imageStruct.isSpin = isSpin;
- imageStruct.isMult = isMult;
- imageStruct.isAnim = isAnim;
- imageStruct.animDirName = animDirName;
- imageStruct.maxAnimFiles = maxAnimFiles;
- [tiffStorage replaceElementAt:(unsigned int)ii
- with:&imageStruct];
- }
- }
- }
- return self;
-
- }
-
- // creates a tiff record in the tiffStorage for every tiff file encountered.
- // the actual tiff lists are built in createTiffs
- // looks in Celestial bundle or .Celestial directory in home directory
-
- - buildTiffStorage
- {
- ImageStruct imageStruct;
-
- tiffStorage = [[Storage allocFromZone:[self zone]] initCount:0
- elementSize:sizeof(imageStruct) description:"{iiii@*}"];
-
- totalTiffCount = [self searchDirectory]; //create list of filenames
-
- return self;
- }
-
- - setTiffDirectory: (char *)directory
- {
- strcpy(tiffDirectory,directory);
- return self;
- }
-
- - (BOOL)isOk:(char *)filename :(int *)isAnim :(int *)isMult :(int *)isSpin
- //checks to make sure the filename is .tiff
- //sets flags for rotate,anim and mult options
-
- {
- char *suffix;
-
- *isSpin = 0;
- *isMult = 0;
- *isAnim = 0;
-
- suffix = rindex(filename,'.');
- if (suffix == 0)
- return NO;
-
- else if(strlen(suffix) != 5)
- return NO;
-
- else if(strncmp(suffix,".tiff",5) == 0){
- *suffix = '\0'; /* strip tiff suffix */
- if([self stringMatch:"mult" :filename])
- *isMult = 1;
- if([self stringMatch:"spin" :filename])
- *isSpin = 1;
- return YES;
-
- }
- else if(strncmp(suffix,".anim",5) == 0){
- *suffix = '\0'; /* strip anim suffix */
- *isAnim = 1;
- if([self stringMatch:"mult" :filename])
- *isMult = 1;
- if([self stringMatch:"spin" :filename])
- *isSpin = 1;
- return YES;
- }
- else
- return NO;
- }
-
-
-
- // look in the directory for all the tiff images
- //if .anim directory encountered then get count and filename
- // create a list of storage objects that will use them
- - (int)searchDirectory
- {
- ImageStruct imageStruct;
- char animDirectory[MAXPATHLEN + 1];
- char filename[MAXPATHLEN + 1];
- long basep;
- char *buf;
- struct direct *dp;
- int cc, fd, fileCount = 0;
- char dirbuf[8192];
- int isAnim,isMult,isSpin,animCount;
-
- if ((fd = open(tiffDirectory, O_RDONLY, 0644)) > 0) {
- cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
- while (cc) {
- dp = (struct direct *)buf;
-
- if ([self isOk:dp->d_name:&isAnim :&isMult :&isSpin]) {
- imageStruct.isAnim = isAnim;
- imageStruct.isMult = isMult;
-
- imageStruct.isSpin = isSpin;
- animCount = 0;
- if(isAnim){
- sprintf(animDirectory,"%s/%s.anim",
- tiffDirectory,dp->d_name);
- animCount = (int)[self isAnimOk:animDirectory :filename];
- if(animCount > 0){
- imageStruct.imageName = NXCopyStringBufferFromZone
- (filename,[self zone]);
- imageStruct.animDirName = NXCopyStringBufferFromZone
- (dp->d_name,[self zone]);
- imageStruct.imageList = NULL;
- imageStruct.maxAnimFiles = animCount;
- [tiffStorage addElement:&imageStruct];
- fileCount++;
- }
- }
- else {
- imageStruct.imageName = NXCopyStringBufferFromZone(dp->d_name,
- [self zone]);
- imageStruct.maxAnimFiles = animCount;
- imageStruct.imageList = NULL;
- imageStruct.animDirName = NULL;
- [tiffStorage addElement:&imageStruct];
- fileCount++;
-
- }
- }
- buf += dp->d_reclen;
- if (buf >= dirbuf + cc) {
- cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
- }
- }
- close(fd);
-
- }
- return fileCount;
- }
-
- - (Storage *)returnTiffStorage
- {
- return tiffStorage;
- }
-
- - setHomeDirFile:(char *)path
- {
- char user[15];
- char *getlogin();
- char *ptr;
- struct passwd *getpwuid(), *pwptr = NULL;
-
- user[0] = 0;
-
- if (((ptr = getlogin()) == NULL) || !user[0])
- {
- if ((pwptr = getpwuid(getuid())) == NULL)
- sprintf(user, "%d", getuid());
- else
- strcpy(user, pwptr->pw_name);
- }
-
- if(user){
- strcpy(path,pwptr->pw_dir);
- strcat(path,"/.Celestial");
- }
- return self;
- }
- - (BOOL)stringMatch:(char *)string1 : (char *)string2
- {
- while(*string2 != '\0'){
- if(strncasecmp(string1,string2,1) == 0){
- if(strncasecmp(string1, string2, strlen(string1)) == 0){
- return YES;
- }
- else{
- string2++;
-
- }
- }
- else
- string2++;
- }
- return NO;
- }
-
- // look in the anim directory for all the tiff images
- // it will return the name of the first file that is named filename.1.tiff
-
- - (int)isAnimOk: (char *)directory :(char *)filename
- {
- // look in the anim directory for all the tiff images
- // it will return the name of the file that is named filename.1.tiff
- // otherwise return NULL
-
- long basep;
- char *buf;
- struct direct *dp;
- int cc = 0;
- int fd = 0;
- short found = 0;
- int fileCount = 0;
- char dirbuf[8192];
- char *suffix = NULL;
-
-
- if ((fd = open(directory, O_RDONLY, 0644)) > 0) {
- cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
- while (cc) {
- dp = (struct direct *)buf;
-
- suffix = rindex(dp->d_name,'.');
- if(strncmp(suffix,".tiff",5) == 0){
- if (!found && [self stringMatch:".1.tiff" :dp->d_name]){
- found = 1; //if found don't look anymore
- strncpy(filename,dp->d_name,
- strlen(dp->d_name)-7);
- filename[(strlen(dp->d_name)-7)] = '\0';
-
- }
- fileCount++;
-
- }
-
- buf += dp->d_reclen;
- if (buf >= dirbuf + cc) {
- cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
- }
- }
- }
- close(fd);
- if(!found) // there was no file "file.1.tiff" in anim dir
- fileCount = 0;
- return fileCount;
- }
- @end
-